
# Copyright (c) 2014, Franklin Brauning V.  All rights reserved.
# 
#    El desarrollo inicial de esta utilidad fue producido
#    por Franklin Brauning <brauningbar@gmail.com>
# 
#    Si consideras que este codigo puede serte util, eres libre
#    de usarlo a conveniencia, pero no olvides mantener la licencia
#    y dar credito al autor.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 
#   * Redistributions of source code must retain the above copyright notice, this
#     list of conditions and the following disclaimer.
# 
#   * Redistributions in binary form must reproduce the above copyright notice,
#     this list of conditions and the following disclaimer in the documentation
#     and/or other materials provided with the distribution.
# 
#   * Neither the name of the author nor the names of its contributors may
#     be used to endorse or promote products derived from this software without
#     specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from django.shortcuts import redirect
from django.http import HttpResponseRedirect
from django.db.models.query import QuerySet

from django.views.generic import View, ListView, CreateView, \
        UpdateView, DeleteView, DetailView, DeleteView, TemplateView

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.contrib import messages
from django.db.models import Q, F

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.conf import settings
from .strings import *
import abstract.models

class TDAuth:
	def markauthsuccess(self):
		self.tdauth_success = True
	def authsucceded(self):
		return hasattr(self, 'tdauth_success')

class AnyGroupLogged(TDAuth):
	@method_decorator(login_required)
	def dispatch(self, request, *a, **kw):
		if self.authsucceded():
			return super().dispatch(request, *a, **kw)

		import configurador.models
		usuario = configurador.models.Usuario.objects.filter(user=request.user).first()
		usuario_activo = not usuario.deleted if usuario else False
		if request.user.is_superuser:
			self.markauthsuccess()
			return super().dispatch(request, *a, **kw)
		elif request.user.is_active and usuario_activo:
			gs = request.user.groups.all()
			if any(map(lambda g: g in self.required_groups, gs)):
				self.markauthsuccess()
				return super().dispatch(request, *a, **kw)
			else:
				messages.error(request, strinvalidgroup)
		else:
			messages.error(request, strinactiveuser)
		return redirect(settings.LOGIN_URL)


class OwnerAnyGroupLogged(TDAuth):
	@method_decorator(login_required)
	def dispatch(self, request, *a, **kw):
		if self.authsucceded():
			return super().dispatch(request, *a, **kw)

		import configurador.models
		usuario = configurador.models.Usuario.objects.filter(user=request.user).first()
		usuario_activo = not usuario.deleted if usuario else False
		if request.user.is_superuser:
			self.markauthsuccess()
			return super().dispatch(request, *a, **kw)
		elif request.user.is_active and usuario_activo:
			obj = getattr(self, 'object', getattr(self, 'get_object', None))
			if callable(obj):
				obj = obj()
			if obj.cuser and self.request.user.id == obj.cuser.id:
				self.markauthsuccess()
				return super().dispatch(request, *a, **kw)
			else:
				gs = request.user.groups.all()
				if any(map(lambda g: g in self.required_groups, gs)):
					self.markauthsuccess()
					return super().dispatch(request, *a, **kw)
				else:
					messages.error(request, strinvalidgroup)
		else:
			messages.error(request, strinactiveuser)
		return redirect(settings.LOGIN_URL)


# sobreescribe vista CreateView para operar correctamente con tracked
# Notar que esta clase corta el flujo del metodo form_valid
#
class CreateView(CreateView):
	def form_valid(self, form):
		x = form.save(commit=False)
		if isinstance(x, abstract.models.tracked):
			x.who(self.request.user)
		x.save()
		return redirect(self.get_success_url())

# sobreescribe vista UpdateView para operar correctamente con tracked
# Notar que esta clase corta el flujo del metodo form_valid
#
class UpdateView(UpdateView):
	def form_valid(self, form):
		x = form.save(commit=False)
		if isinstance(x, abstract.models.tracked):
			x.who(self.request.user)
		x.save()
		return redirect(self.get_success_url())

def nonmergepts(obj):
	if type(obj) is QuerySet:
		if hasattr(obj.model, 'ismergepoint'):
			return obj.filter(merge_parent1__isnull=True,
			  merge_parent2__isnull=True, merge_child__isnull=True)
		return obj

	trymerging = True
	ismerging = False
	def ismerge(x):
		nonlocal trymerging, ismerging
		if trymerging:
			trymerging = False
			ismerging = hasattr(x, 'ismergepoint')
		return x.ismergepoint() if ismerging else False

	return filter(lambda x:not ismerge(x), obj)

def mergepts(obj):
	if type(obj) is QuerySet:
		if hasattr(obj.model, 'ismergepoint'):
			return obj.filter(Q(merge_child__isnull=False) |
			  Q(merge_parent1__isnull=False) |
			  Q(merge_parent2__isnull=False))
		return obj

	trymerging = True
	ismerging = False
	def ismerge(x):
		nonlocal trymerging, ismerging
		if trymerging:
			trymerging = False
			ismerging = hasattr(x, 'ismergepoint')
		return x.ismergepoint() if ismerging else False

	return filter(lambda x:ismerge(x), obj)

def fossils(obj):
	if type(obj) is QuerySet:
		return obj.filter(current=True)
	return filter(lambda x:x.current, obj)

def deleteds(obj):
	if type(obj) is QuerySet:
		return obj.filter(deleted=True)
	return filter(lambda x:x.deleted, obj)

def actives(obj):
	if type(obj) is QuerySet:
		return obj.filter(deleted=False)
	return filter(lambda x:not x.deleted, obj)

def tips(obj):
	return actives(fossils(obj))

def nmtips(obj):
	return actives(nonmergepts(fossils(obj)))

def nmfossils(obj):
	return nonmergepts(fossils(obj))

class FossilListView(ListView):
	def get_queryset(self):
		return fossils(nonmergepts(super(FossilListView, self).get_queryset()))


class ListAll(FossilListView):
	def get_context_data(self, **kw):
		context = super(ListAll, self).get_context_data(**kw)
		context['actives'] = True
		context['hidden'] = True
		return context


class ListHidden(FossilListView):
	def get_context_data(self, **kw):
		context = super(ListHidden, self).get_context_data(**kw)
		context['hidden'] = True
		return context

	def get_queryset(self):
		return deleteds(super(ListHidden, self).get_queryset())


class ListActives(FossilListView):
	def get_context_data(self, **kw):
		context = super(ListActives, self).get_context_data(**kw)
		context['actives'] = True
		return context

	def get_queryset(self, **kw):
		return actives(super(ListActives, self).get_queryset())


class UndoView(UpdateView):
	def get_success_url(self):
		return "#"

	def get(self, *a, **kw):
		self.get_object().undo()
		return redirect(self.get_success_url())


class RedoView(UpdateView):
	def get_success_url(self):
		return "#"

	def get(self, *a, **kw):
		self.get_object().redo()
		return redirect(self.get_success_url())


class DeleteViewGet(DeleteView):
	def get(self, *a, **kw):
		import abstract.models
		obj = self.get_object()
		if isinstance(obj, abstract.models.tracked):
			obj.who(self.request.user)
		obj.delete()
		return redirect(self.get_success_url())

class UndeleteViewGet(DeleteView):
	def get(self, *a, **kw):
		import abstract.models
		obj = self.get_object()
		if isinstance(obj, abstract.models.tracked):
			obj.who(self.request.user)
		obj.undelete()
		return redirect(self.get_success_url())


def html_injectsubmit(formname, code):
	x,y,z = code.partition('>')
	if x.endswith('/'):
		x = x[:-1]
		y = '/'+y

	sub = 'onclick="document.forms.%s.submit();"'
	return "%s %s %s%s" % (x, sub, y, z)


def html_checkbox(b):
    return "<input type=checkbox %s onchange='this.checked=!this.checked;'>" % (
    "checked" if b else "")


def paginated(func):
	def w(self, *a, **kw):
		try:
			by = int(self.kwargs.get('by'))
		except TypeError:
			by = 12
		paginator = Paginator(func(self, *a, **kw), by)
		page = self.request.GET.get('page')
		try:
			return paginator.page(page)
		except PageNotAnInteger:
			return paginator.page(1)
		except EmptyPage:
		# If page is out of range (e.g. 9999), deliver last page of results.
			return paginator.page(paginator.num_pages)
	return w

def qpaginated(self, query, by=12):
	try:
		by = int(self.kwargs.get('by'))
	except TypeError:
		pass
	paginator = Paginator(query, by)
	page = self.request.GET.get('page')
	try:
		return paginator.page(page)
	except PageNotAnInteger:
		return paginator.page(1)
	except EmptyPage:
	# If page is out of range (e.g. 9999), deliver last page of results.
		return paginator.page(paginator.num_pages)
